package com.common.utils;

import com.baomidou.mybatisplus.core.batch.MybatisBatch;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Component
@Slf4j
public class MysqlBatchUtil {

    @Resource(name = "mysqlSqlSessionFactory")
    private SqlSessionFactory mysqlSqlSessionFactory;

    /**
     * 批量插入
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @return 影响行数
     */
    public <T, M extends BaseMapper<T>> int batchInsert(List<T> dataList, Class<M> mapperClazz) {
        if (dataList == null || dataList.isEmpty()) {
            log.warn("批量插入数据列表为空");
            return 0;
        }

        try {
            MybatisBatch<T> mybatisBatch = new MybatisBatch<>(mysqlSqlSessionFactory, dataList);
            MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperClazz);
            List<BatchResult> results = mybatisBatch.execute(method.insert());
            return calculateTotalRowsAffected(results);
        } catch (Exception e) {
            log.error("批量插入数据失败, 数据量: {}, Mapper: {}", dataList.size(), mapperClazz.getSimpleName(), e);
            throw new RuntimeException("批量插入数据失败", e);
        }
    }

    /**
     * 批量更新
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @return 影响行数
     */
    public <T, M extends BaseMapper<T>> int batchUpdate(List<T> dataList, Class<M> mapperClazz) {
        if (dataList == null || dataList.isEmpty()) {
            log.warn("批量更新数据列表为空");
            return 0;
        }

        try {
            MybatisBatch<T> mybatisBatch = new MybatisBatch<>(mysqlSqlSessionFactory, dataList);
            MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperClazz);
            List<BatchResult> results = mybatisBatch.execute(method.updateById());
            return calculateTotalRowsAffected(results);
        } catch (Exception e) {
            log.error("批量更新数据失败, 数据量: {}, Mapper: {}", dataList.size(), mapperClazz.getSimpleName(), e);
            throw new RuntimeException("批量更新数据失败", e);
        }
    }

    /**
     * 批量删除（根据实体）
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @return 影响行数
     */
    public <T, M extends BaseMapper<T>> int batchDelete(List<T> dataList, Class<M> mapperClazz) {
        if (dataList == null || dataList.isEmpty()) {
            log.warn("批量删除数据列表为空");
            return 0;
        }

        try {
            MybatisBatch<T> mybatisBatch = new MybatisBatch<>(mysqlSqlSessionFactory, dataList);
            MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperClazz);
            List<BatchResult> results = mybatisBatch.execute(method.deleteById());
            return calculateTotalRowsAffected(results);
        } catch (Exception e) {
            log.error("批量删除数据失败, 数据量: {}, Mapper: {}", dataList.size(), mapperClazz.getSimpleName(), e);
            throw new RuntimeException("批量删除数据失败", e);
        }
    }

    /**
     * 根据ID批量删除
     *
     * @param idList      ID列表
     * @param mapperClazz Mapper类
     * @return 影响行数
     */
    public <T, M extends BaseMapper<T>> int batchDeleteByIds(List<?> idList, Class<M> mapperClazz) {
        if (idList == null || idList.isEmpty()) {
            log.warn("批量删除ID列表为空");
            return 0;
        }

        try {
            MybatisBatch<?> mybatisBatch = new MybatisBatch<>(mysqlSqlSessionFactory, idList);
            MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperClazz);
            List<BatchResult> results = mybatisBatch.execute(method.deleteById());
            return calculateTotalRowsAffected(results);
        } catch (Exception e) {
            log.error("根据ID批量删除失败, ID数量: {}, Mapper: {}", idList.size(), mapperClazz.getSimpleName(), e);
            throw new RuntimeException("根据ID批量删除失败", e);
        }
    }

    /**
     * 批量操作（自定义方法）
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @param methodName  方法名
     * @return 影响行数
     */
    public <T, M extends BaseMapper<T>> int batchOperation(List<T> dataList, Class<M> mapperClazz, String methodName) {
        if (dataList == null || dataList.isEmpty()) {
            log.warn("批量操作数据列表为空, 方法: {}", methodName);
            return 0;
        }

        try {
            MybatisBatch<T> mybatisBatch = new MybatisBatch<>(mysqlSqlSessionFactory, dataList);
            MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperClazz);
            List<BatchResult> results = mybatisBatch.execute(method.get(methodName));
            return calculateTotalRowsAffected(results);
        } catch (Exception e) {
            log.error("批量操作失败, 方法: {}, 数据量: {}, Mapper: {}", methodName, dataList.size(), mapperClazz.getSimpleName(), e);
            throw new RuntimeException("批量操作失败, 方法: " + methodName, e);
        }
    }

    /**
     * 批量操作（使用函数式接口）
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @param operation   操作函数
     * @return 影响行数
     */
//    public <T, M extends BaseMapper<T>> int batchOperation(List<T> dataList, Class<M> mapperClazz,
//                                                           Function<MybatisBatch.Method<M>, Function<M, String>> operation) {
//        if (dataList == null || dataList.isEmpty()) {
//            log.warn("批量操作数据列表为空");
//            return 0;
//        }
//
//        try {
//            MybatisBatch<T> mybatisBatch = new MybatisBatch<>(mysqlSqlSessionFactory, dataList);
//            MybatisBatch.Method<T> method = new MybatisBatch.Method<>(mapperClazz);
//            Function<M, String> batchMethod = operation.apply((MybatisBatch.Method<M>) method);
//            List<BatchResult> results = mybatisBatch.execute((BatchMethod<T>) batchMethod);
//            return calculateTotalRowsAffected(results);
//        } catch (Exception e) {
//            log.error("批量操作失败, 数据量: {}, Mapper: {}", dataList.size(), mapperClazz.getSimpleName(), e);
//            throw new RuntimeException("批量操作失败", e);
//        }
//    }

    /**
     * 计算总影响行数
     *
     * @param results 批处理结果
     * @return 总影响行数
     */
    private int calculateTotalRowsAffected(List<BatchResult> results) {
        if (results == null || results.isEmpty()) {
            return 0;
        }

        int totalRows = 0;
        for (BatchResult result : results) {
            int[] updateCounts = result.getUpdateCounts();
            if (updateCounts != null) {
                for (int count : updateCounts) {
                    if (count >= 0) { // 只统计非负值，-2表示BATCH_EXECUTION_SKIP
                        totalRows += count;
                    }
                }
            }
        }
        return totalRows;
    }

    /**
     * 批量插入并返回是否全部成功
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @return 是否全部成功
     */
    public <T, M extends BaseMapper<T>> boolean batchInsertWithResult(List<T> dataList, Class<M> mapperClazz) {
        if (dataList == null || dataList.isEmpty()) {
            return true;
        }

        int affectedRows = batchInsert(dataList, mapperClazz);
        return affectedRows == dataList.size();
    }

    /**
     * 批量更新并返回是否全部成功
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @return 是否全部成功
     */
    public <T, M extends BaseMapper<T>> boolean batchUpdateWithResult(List<T> dataList, Class<M> mapperClazz) {
        if (dataList == null || dataList.isEmpty()) {
            return true;
        }

        int affectedRows = batchUpdate(dataList, mapperClazz);
        return affectedRows == dataList.size();
    }

    /**
     * 分批次处理大数据量
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @param batchSize   批次大小
     * @param operation   操作类型
     * @return 总影响行数
     */
    public <T, M extends BaseMapper<T>> int batchProcessInChunks(List<T> dataList, Class<M> mapperClazz,
                                                                 int batchSize, String operation) {
        if (dataList == null || dataList.isEmpty()) {
            return 0;
        }

        int totalRows = 0;
        int totalSize = dataList.size();
        int fromIndex = 0;

        while (fromIndex < totalSize) {
            int toIndex = Math.min(fromIndex + batchSize, totalSize);
            List<T> batchList = dataList.subList(fromIndex, toIndex);

            try {
                int batchRows;
                switch (operation.toLowerCase()) {
                    case "insert":
                        batchRows = batchInsert(batchList, mapperClazz);
                        break;
                    case "update":
                        batchRows = batchUpdate(batchList, mapperClazz);
                        break;
                    case "delete":
                        batchRows = batchDelete(batchList, mapperClazz);
                        break;
                    default:
                        throw new IllegalArgumentException("不支持的批量操作类型: " + operation);
                }
                totalRows += batchRows;
                log.debug("批次处理进度: {}-{}/{}，本次影响行数: {}", fromIndex, toIndex, totalSize, batchRows);
            } catch (Exception e) {
                log.error("批次处理失败, 范围: {}-{}, 操作: {}", fromIndex, toIndex, operation, e);
                throw new RuntimeException("批次处理失败", e);
            }

            fromIndex = toIndex;
        }

        log.info("批量{}完成, 总数据量: {}, 总影响行数: {}", operation, totalSize, totalRows);
        return totalRows;
    }

    /**
     * 分批次处理大数据量（使用函数式操作）
     *
     * @param dataList    数据列表
     * @param mapperClazz Mapper类
     * @param batchSize   批次大小
     * @param operation   操作函数
     * @return 总影响行数
     */
//    public <T, M extends BaseMapper<T>> int batchProcessInChunks(List<T> dataList, Class<M> mapperClazz,
//                                                                 int batchSize,
//                                                                 Function<MybatisBatch.Method<M>, Function<M, String>> operation) {
//        if (dataList == null || dataList.isEmpty()) {
//            return 0;
//        }
//
//        int totalRows = 0;
//        int totalSize = dataList.size();
//        int fromIndex = 0;
//
//        while (fromIndex < totalSize) {
//            int toIndex = Math.min(fromIndex + batchSize, totalSize);
//            List<T> batchList = dataList.subList(fromIndex, toIndex);
//
//            try {
//                int batchRows = batchOperation(batchList, mapperClazz, operation);
//                totalRows += batchRows;
//                log.debug("批次处理进度: {}-{}/{}，本次影响行数: {}", fromIndex, toIndex, totalSize, batchRows);
//            } catch (Exception e) {
//                log.error("批次处理失败, 范围: {}-{}", fromIndex, toIndex, e);
//                throw new RuntimeException("批次处理失败", e);
//            }
//
//            fromIndex = toIndex;
//        }
//
//        log.info("批量操作完成, 总数据量: {}, 总影响行数: {}", totalSize, totalRows);
//        return totalRows;
//    }
}